/**
 * parentId 形式数据转 children 形式
 * @param option ToTreeOption
 */
export function toTree(option) {
  const data = option.data;
  const idField = option.idField || 'id';
  const parentIdField = option.parentIdField || 'parentId';
  const childrenField = option.childrenField || 'children';
  const parentIdIsNull = option.parentId == null;
  const parentId = parentIdIsNull ? [] : option.parentId;
  const parentIdIsArray = Array.isArray(parentId);
  const addParentIds = option.addParentIds;
  const parentIdsField = option.parentIdsField || 'parentIds';
  const parentIds = option.parentIds ?? [];

  if (data == null) {
    return [];
  }

  if (parentIdIsNull) {
    data.forEach((d) => {
      if (
        !data.some((t) => d[parentIdField] == t[idField]) &&
        !parentId.includes(d[parentIdField])
      ) {
        parentId.push(d[parentIdField]);
      }
    });
  }

  const result = [];
  data.forEach((d) => {
    if (d[idField] == d[parentIdField]) {
      const error = {
        [idField]: d[idField],
        [parentIdField]: d[parentIdField],
        data: d
      };
      console.error('data error:', error);
      throw new Error('data error');
    }
    if (
      parentIdIsArray
        ? parentId.includes(d[parentIdField])
        : d[parentIdField] == parentId
    ) {
      const t = { ...d };
      const children = toTree({
        data,
        idField,
        parentIdField,
        childrenField,
        parentId: d[idField],
        addParentIds,
        parentIdsField,
        parentIds: [...parentIds, d[idField]]
      });
      if (children.length > 0) {
        t[childrenField] = children;
      }
      if (addParentIds) {
        t[parentIdsField] = parentIds;
      }
      result.push(t);
    }
  });
  return result;
}

/**
 * 遍历 children 形式数据
 * @param data 数据
 * @param callback 回调
 * @param childrenField children 字段名
 * @param parent 当前的父级
 */
export function eachTree(data, callback, childrenField = 'children', parent) {
  if (!data) {
    return;
  }
  for (let i = 0; i < data.length; i++) {
    const flag = callback ? callback(data[i], i, parent) : void 0;
    if (flag === false) {
      return false;
    }
    if (data[i][childrenField]?.length) {
      if (
        eachTree(data[i][childrenField], callback, childrenField, data[i]) ===
        false
      ) {
        return false;
      }
    }
  }
}

/**
 * 处理每一项数据
 * @param item 当前的数据
 * @param index 当前的索引
 * @param parent 当前的父级
 * @param formatter 格式器
 * @param childrenField children 字段名
 * @param resultChildrenField 返回后的 children 字段名
 * @param afterFormatter 后置格式器
 */
function formatTreeItem(
  item,
  index,
  parent,
  formatter,
  childrenField = 'children',
  resultChildrenField = 'children',
  afterFormatter
) {
  const result = [];
  const itemResult = formatter(item, index, parent);
  if (itemResult === 'flatChildren') {
    const children = item[childrenField];
    if (children) {
      children.forEach((c, j) => {
        const childItems = formatTreeItem(
          c,
          j,
          item,
          formatter,
          childrenField,
          resultChildrenField,
          afterFormatter
        );
        childItems.forEach((childItem) => {
          const afterItem = afterFormatter
            ? afterFormatter(childItem)
            : childItem;
          if (afterItem) {
            result.push(afterItem);
          }
        });
      });
    }
  } else if (itemResult) {
    if (item[childrenField] != null) {
      itemResult[resultChildrenField] = mapTree(
        item[childrenField],
        formatter,
        childrenField,
        resultChildrenField,
        afterFormatter,
        itemResult
      );
    }
    const afterItem = afterFormatter ? afterFormatter(itemResult) : itemResult;
    if (afterItem) {
      result.push(afterItem);
    }
  }
  return result;
}

/**
 * 处理 children 形式数据
 * @param data 数据
 * @param formatter 格式器
 * @param childrenField children 字段名
 * @param resultChildrenField 返回后的 children 字段名
 * @param afterFormatter 后置格式器
 * @param parent 当前的父级
 */
export function mapTree(
  data,
  formatter,
  childrenField = 'children',
  resultChildrenField = 'children',
  afterFormatter,
  parent
) {
  const result = [];
  if (data) {
    data.forEach((d, i) => {
      const items = formatTreeItem(
        d,
        i,
        parent,
        formatter,
        childrenField,
        resultChildrenField,
        afterFormatter
      );
      items.forEach((item) => {
        result.push(item);
      });
    });
  }
  return result;
}

/**
 * 查找 children 形式数据
 * @param data 数据
 * @param predicate 查找条件
 * @param childrenField children 字段名
 */
export function findTree(data, predicate, childrenField) {
  let temp;
  eachTree(
    data,
    (d, i) => {
      if (predicate(d, i)) {
        temp = d;
        return false;
      }
    },
    childrenField
  );
  return temp;
}

/**
 * 检查是否全屏
 */
export function checkFullscreen() {
  return !!(
    document.fullscreenElement ||
    document.webkitFullscreenElement ||
    document.mozFullScreenElement ||
    document.msFullscreenElement
  );
}

/**
 * 退出全屏
 */
export function exitFullscreen() {
  const func =
    document.exitFullscreen ||
    document.exitFullScreen ||
    document.webkitCancelFullScreen ||
    document.mozCancelFullScreen ||
    document.msExitFullscreen;
  func && func.call(document);
}

/**
 * 全屏
 * @param el HTMLElement
 */
export function requestFullscreen(el) {
  if (el == null) {
    el = document.documentElement;
  }
  const func =
    el.requestFullscreen ||
    el.requestFullScreen ||
    el.webkitRequestFullScreen ||
    el.mozRequestFullScreen ||
    el.msRequestFullScreen;
  if (!func) {
    throw new Error('您的浏览器不支持全屏模式');
  }
  func.call(el);
}

/**
 * 百度地图坐标转高德地图坐标
 * @param point 坐标
 */
export function bd09ToGcj02(point) {
  const x_pi = (3.141592653589793 * 3000.0) / 180.0;
  const x = point.lng - 0.0065;
  const y = point.lat - 0.006;
  const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
  const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
  return {
    lng: z * Math.cos(theta),
    lat: z * Math.sin(theta)
  };
}

/**
 * 高德地图坐标转百度地图坐标
 * @param point 坐标
 */
export function gcj02ToBd09(point) {
  const x_pi = (3.141592653589793 * 3000.0) / 180.0;
  const x = point.lng;
  const y = point.lat;
  const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
  const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
  return {
    lng: z * Math.cos(theta) + 0.0065,
    lat: z * Math.sin(theta) + 0.006
  };
}

/**
 * 生成 m 到 n 的随机数
 * @param m 最小值(包含)
 * @param n 最大值(不包含)
 */
export function random(m, n) {
  return Math.floor(Math.random() * (m - n) + n);
}

/**
 * 生成随机字符串
 * @param length 长度
 * @param radix 基数
 */
export function uuid(length = 32, radix) {
  const str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  let result = '';
  for (let i = 0; i < length; i++) {
    result += str.charAt(Math.floor(Math.random() * (radix || str.length)));
  }
  return result;
}

/**
 * 数字千分位
 * @param num 数字
 */
export function formatNumber(num) {
  return String(num ?? '').replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, '$1,');
}

/**
 * 赋值不改变原字段
 * @param target 目标对象
 * @param source 源对象
 * @param excludes 排除的字段
 */
export function assignObject(target, source, excludes) {
  Object.keys(target).forEach((key) => {
    if (!excludes?.includes?.(key)) {
      target[key] = source[key];
    }
  });
  return target;
}

/**
 * 复制字符串
 * @param text 字符串
 */
export async function copyText(text) {
  if (typeof navigator?.clipboard?.writeText === 'function') {
    await navigator.clipboard.writeText(text);
    return;
  }
  const el = document.createElement('textarea');
  el.value = text;
  el.style.position = 'fixed';
  el.style.top = '-200px';
  el.style.left = '-200px';
  el.style.width = '100px';
  el.style.height = '100px';
  document.body.appendChild(el);
  el.focus();
  el.select();
  if (!document.execCommand('copy')) {
    el.remove();
    return Promise.reject(new Error('浏览器不支持复制'));
  }
  el.remove();
}

/**
 * 查找直接子元素
 * @param parentEl 父元素
 * @param className 根据类名查找
 * @param attr 根据属性查找
 */
export function queryChild(parentEl, className, attr) {
  return Array.from(parentEl?.children ?? []).find((el) => {
    if (className && !el.classList.contains(className)) {
      return false;
    }
    if (attr != null && attr[0] != null) {
      if (el.getAttribute(attr[0]) != attr[1]) {
        return false;
      }
    }
    return true;
  });
}

/**
 * 判断是否是外链
 * @param url 地址
 */
export function isExternalLink(url) {
  return !!(
    url &&
    (url.startsWith('http://') ||
      url.startsWith('https://') ||
      url.startsWith('//'))
  );
}
